/**
 * Excel文件的导入导出处理工具
 * 
 * 计划实现功能：树形表、字典url、复杂表头、序号列、映射功能
 * 计划攻关技术点：表格样式（字体大小、列宽行高、背景文字颜色、边框样式）、注释功能
 *
 * 参数参考：
 * option: {
 *   title: '标题', // 默认没有标题
 *   sequence: false, // 序号列,暂未实现
 *   column: [
 *     {
 *       label: '中文名称',
 *       prop: 'key',
 *       index: 1, // 顺序
 *       dicData: [
 *         {
 *           label: '显示内容',
 *           value: '值',
 *         }
 *       ], // 暂未实现
 *       props: {label:'label',value:'value'} // 暂未实现
 *       children:[] // 复杂表头,暂未实现
 *     }
 *   ]
 * },
 * isMap: true // 默认启用映射
 */
import XLSX from '../../../assets/xlsx.full.min.js'

// 标题 内容 头

// 导入
let importXlsx = (option) => {
  return new Promise((resolve, reject) => {
    let isTitle = option.title ? 1 : 0
    let inputEl = document.createElement('input')
    inputEl.setAttribute('type', 'file')
    inputEl.setAttribute('accept', '.xlsx')
    inputEl.addEventListener('change', (e) => {
      let files = e.target.files;
      if (files.length == 0) return;
      let f = files[0];
      if (!/\.xlsx$/g.test(f.name)) {
        reject("仅支持读取xlsx格式！")
        return;
      }
      readWorkbookFromLocalFile(f, (workbook) => {
        let sheetNames = workbook.SheetNames; // 工作表名称集合
        let worksheet = workbook.Sheets[sheetNames[0]]; // 只读取第一张sheet
        let { keys } = getHeaderRow(worksheet, isTitle, option)
        // console.log('keys',keys)
        let json = XLSX.utils.sheet_to_json(worksheet, { range: isTitle, header: 1 });
        json = json.filter(item => item && item.length)
        let disData = dataDistribution(keys, json)
        resolve({ ...disData, workbook })
      });
      inputEl.remove()
    })
    inputEl.click()
  })
}

// 导出
let exportXlsx = (data, option) => {
  return new Promise((resolve, reject) => {
    try {
      // 根据option将data处理成aoa格式，并转成sheet（复杂表头处理合并项）
      let header = sortHeader(option.column)
      let aoa = createAoa(data, header, option)
      let sheet = XLSX.utils.aoa_to_sheet(aoa);
      // 合并头
      if (option.title) {
        sheet['!merges'] = [
          { s: { r: 0, c: 0 }, e: { r: 0, c: (header.length || 1) - 1 } }
        ]
      }
      let blob = sheet2blob(sheet)
      // console.log(sheet)
      let timeStr = getTimeStr()
      // 导出文件名称由表名加时间组成
      openDownloadDialog(blob, `${option.title || '新表单'}-${timeStr}.xlsx`);
      resolve(sheet)
      // resolve('测试')
    }
    catch (err) {
      reject(err)
    }
  })
}

// 生成aoa
function createAoa(data, header, option) {
  // if (!data || !data.length || !header || !header.length) return []
  if (!header || !header.length) return []
  let aoa = []
  // 标题
  option.title && aoa.push([option.title])
  // 表头
  let h = header.map(item => item.label)
  aoa.push(h)
  data?.forEach(item => {
    let row = header.map(el => item[el.prop]?.toString() || null)
    aoa.push(row)
  })
  return aoa
}

// 排序标题
function sortHeader(column) {
  let orderedH = []
  let defaultH = []
  column.forEach(item => {
    if (item.index || item.index == 0) return orderedH.push(item)
    defaultH.push(item)
  })
  orderedH.sort((e, s) => e.index - s.index)
  return [...orderedH, ...defaultH]
}

// 导入数据分配
function dataDistribution(keys, json) {
  if (!keys || !json || !json.length) return {}
  const header = {}
  json[0].forEach((el, i) => {
    if (!keys[i]) return
    let key = keys[i]
    header[key.prop || key.excelHeader] = el
  })
  const data = []
  for (let i = 1; i < json.length; i++) {
    let column = {}
    json[i].forEach((el, i) => {
      if (!keys[i]) return
      let key = keys[i]
      column[key.prop || key.excelHeader] = el
    })
    data.push(column)
  }
  return { header, data }
}

// 读取本地excel文件
function readWorkbookFromLocalFile(file, callback) {
  let reader = new FileReader();
  reader.onload = function (e) {
    let data = e.target.result;
    let workbook = XLSX.read(data, { type: "binary", sheetRows: 0 });
    if (callback) callback(workbook);
  };
  reader.readAsBinaryString(file);
}

// 表头处理
function getHeaderRow(sheet, isTitle, option) {
  const headers = [];
  /* sheet['!ref']表示所有单元格的范围，例如从A1到F8则记录为 A1:F8*/
  const range = XLSX.utils.decode_range(sheet["!ref"]);
  // console.log('range',range)
  let C,
    R = range.s.r + isTitle; /* 从第一行开始 */
  /* 按列进行数据遍历 */
  for (C = range.s.c; C <= range.e.c; ++C) {
    /* 查找第一行中的单元格 */
    const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })];

    let hdr = "UNKNOWN " + C; // <-- 进行默认值设置
    if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);

    headers.push(hdr);
  }
  const keys = {}
  headers.forEach((item, index) => {
    let columns = option?.column?.filter(el => el.label == item)
    let column = columns?.length ? columns[0] : {}
    // keys.push({
    //   label: column.label || '',
    //   prop: column.prop || '',
    //   excelHeader: item,
    //   excelIndex: index
    // })
    keys[index] = {
      label: column.label || '',
      prop: column.prop || '',
      excelHeader: item
    }
  })
  return { headers, keys };
}

// 获取时间字符串
function getTimeStr() {
  let date = new Date();
  let month = date.getMonth() + 1;
  let D = date.getDate();
  let h = date.getHours();
  let m = date.getMinutes();
  let timeStr = `${JSON.stringify(date.getFullYear()).slice(2)}${month < 10 ? "0" + month : month
    }${D < 10 ? "0" + D : D}${h < 10 ? "0" + h : h}${m < 10 ? "0" + m : m}`;
  return timeStr
}

// 将一个sheet转成最终的excel文件的blob对象，然后利用URL.createObjectURL下载
function sheet2blob(sheet, sheetName) {
  sheetName = sheetName || "sheet1";
  let workbook = {
    SheetNames: [sheetName],
    Sheets: {},
  };
  workbook.Sheets[sheetName] = sheet;
  // 生成excel的配置项
  let wopts = {
    bookType: "xlsx", // 要生成的文件类型
    bookSST: false, // 是否生成Shared String Table，官方解释是，如果开启生成速度会下降，但在低版本IOS设备上有更好的兼容性
    type: "binary",
  };
  let wbout = XLSX.write(workbook, wopts);
  let blob = new Blob([s2ab(wbout)], { type: "application/octet-stream" });
  // 字符串转ArrayBuffer·   1                                                
  function s2ab(s) {
    let buf = new ArrayBuffer(s.length);
    let view = new Uint8Array(buf);
    for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
    return buf;
  }
  return blob;
}

/**
 * 通用的打开下载对话框方法，没有测试过具体兼容性
 * @param url 下载地址，也可以是一个blob对象，必选
 * @param saveName 保存文件名，可选
 */
function openDownloadDialog(url, saveName) {
  if (typeof url == "object" && url instanceof Blob) {
    url = URL.createObjectURL(url); // 创建blob地址
  }
  let aLink = document.createElement("a");
  aLink.href = url;
  aLink.download = saveName || ""; // HTML5新增的属性，指定保存文件名，可以不要后缀，注意，file:///模式下不会生效
  let event;
  if (window.MouseEvent) event = new MouseEvent("click");
  else {
    event = document.createEvent("MouseEvents");
    event.initMouseEvent(
      "click", true, false, window,
      0, 0, 0, 0, 0,
      false, false, false, false,
      0, null
    );
  }
  aLink.dispatchEvent(event);
  aLink.remove()
}

export default { importXlsx, exportXlsx }